// Copyright (c) 2000 Just Objects B.V. <just@justobjects.nl>
// Distributable under LGPL license. See terms of license at gnu.org.

package nl.justobjects.pushlet.core;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Subscribes to events from a Publisher using the HTTP protocol.
 *
 * @version $Id: HTTPSubscriber.java,v 1.5 2003/08/15 08:37:40 justb Exp $
 * @author Just van den Broecke - Just Objects &copy;
 **/
abstract public class HTTPSubscriber implements Subscriber {
	String mySubject = null;
	String myAddress = null;
	String format = null;
	ClientAdapter clientAdapter = null;
	BlockingQueue eventQueue = new BlockingQueue(32);

	public volatile static int count = 0;

	public HTTPSubscriber() {
	}

	/** Return (remote) IP address of client. */
	public String getAddress() {
		return myAddress;
	}

	/** Return number of instances. */
	public static int getCount() {
		return count;
	}

	/** Return Event format to send to client. */
	public String getFormat() {
		return format;
	}

	/** Return subject subscribed to. */
	public String getSubject() {
		return mySubject;
	}

	/** Default bailing out: remove ourselves from Publisher. */
	protected void bailout() {
		Publisher.getInstance().leave(this);
		count--;
	}

	/** Create client notifier based on "client" parameter passed in request and required protocol. */
	abstract protected ClientAdapter createClientAdapter(HttpServletRequest httpServletRequest,
														 HttpServletResponse httpServletResponse) throws IOException;

	/** Create client notifier based on "client" parameter passed in request. */
	public void init(HttpServletRequest httpServletRequest,
						HttpServletResponse httpServletResponse) throws IOException {

		myAddress = httpServletRequest.getRemoteAddr();
		if (myAddress == null) {
			myAddress = "unknown-host";
		}

		mySubject = httpServletRequest.getParameter("subject");

		// Determine format in which Events should be sent to the client.
		format = httpServletRequest.getParameter("format");

		// Default assume a browser window on the other end.
		if (format == null || format.length() == 0) {
			format = FORMAT_JAVASCRIPT;
		}

		// Just to try to prevent caching in any form.

		// Set to expire far in the past.
		httpServletResponse.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT");

		// Set standard HTTP/1.1 no-cache headers.
		httpServletResponse.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");

		// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
		httpServletResponse.addHeader("Cache-Control", "post-check=0, pre-check=0");

		// Set standard HTTP/1.0 no-cache header.
		httpServletResponse.setHeader("Pragma", "no-cache");

		// Create and start client-specific adapter.
		clientAdapter = createClientAdapter(httpServletRequest, httpServletResponse);
		clientAdapter.init(httpServletRequest, httpServletResponse);
		clientAdapter.start();

		// Get Publisher instance we'll listen to.
		Publisher.getInstance().join(this);
		count++;
	}

	/** Process events in queue and push to clients. */
	abstract public void processEvents() throws IOException;

	/** Determine if we should receive event. */
	synchronized public boolean match(Event event) {
		if (mySubject == null) {
			return false;
		}

		// True when subject starts with the same string as mine
		return event.getSubject().startsWith(mySubject);
	}

	/** Event from Publisher: enqueue it. */
	synchronized public void send(Event theEvent) {
		// p("send: queue event: "+theEvent.getSubject());

		// Put event in queue; may block if queue full
		try {
			if (!eventQueue.enQueue(theEvent, 30000)) {
				Log.warn("HTTPSubscriber: [" + this + "] queue full for long time, bailing out...");
				bailout();
			}
		}
		catch (InterruptedException ie) {
			bailout();
		}

		// Event in queue; see processEvents() where it is handled by another thread.
		return;
	}

	public String toString() {
		return myAddress + " subject [" + mySubject + "]";
	}
}

/*
 * $Log: HTTPSubscriber.java,v $
 * Revision 1.5  2003/08/15 08:37:40  justb
 * fix/add Copyright+LGPL file headers and footers
 *
 * Revision 1.4  2003/08/12 09:57:05  justb
 * replaced all print statements to Log.*() calls
 *
 * Revision 1.3  2003/05/19 21:56:29  justb
 * various fixes for applet clients
 *
 * Revision 1.2  2003/05/18 16:15:08  justb
 * support for XML encoded Events
 *
 * Revision 1.1.1.1  2002/09/24 21:02:31  justb
 * import to sourceforge
 *
 * Revision 1.1.1.1  2002/09/20 22:48:18  justb
 * import to SF
 *
 * Revision 1.1.1.1  2002/09/20 14:19:03  justb
 * first import into SF
 *
 * Revision 1.3  2002/04/15 20:42:41  just
 * reformatting and renaming GuardedQueue to BlockingQueue
 *
 * Revision 1.2  2000/08/21 20:48:29  just
 * added CVS log and id tags plus copyrights
 *
 *
 */
